home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / X11R4 / cmds / X / os / sprite.X11R3 / tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-16  |  19.3 KB  |  683 lines

  1. /*-
  2.  * tcp.c --
  3.  *    Functions to communicate with clients over a TCP connection.
  4.  *
  5.  * Copyright (c) 1987 by the Regents of the University of California
  6.  *
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  *
  15.  *
  16.  */
  17. #ifndef lint
  18. static char rcsid[] =
  19. "$Header: /b/X/src/cmds/Xsprite/os/RCS/tcp.c,v 1.7 89/08/15 21:34:45 ouster Exp $ SPRITE (Berkeley)";
  20. #endif lint
  21.  
  22. #ifdef TCPCONN
  23.  
  24. /*
  25.  * The following includes must be first, or the file won't compile.
  26.  */
  27.  
  28. #define Time SpriteTime
  29. #include    <fs.h>
  30. #undef Time
  31. #include    <stdlib.h>
  32.  
  33. #include    "spriteos.h"
  34. #include    "Xproto.h"
  35. #include    "opaque.h"
  36.  
  37. #include    <bit.h>
  38. #include    <errno.h>
  39. #include    <signal.h>
  40. #include    <sys/types.h>
  41. #include    <sys/socket.h>
  42. #include    <sys/time.h>
  43. #include    <netinet/in.h>
  44.  
  45. int    TCP_Conn;     /* Passive socket for listening */
  46.  
  47. typedef struct {
  48.     int              streamID;     /* Active socket for client */
  49.     ClientPtr      client;       /* Back pointer to Client descriptor */
  50.     Address       buffer;       /* Input buffer */
  51.     Address       bufPtr;       /* Current position in buffer */
  52.     int              numBytes;     /* Bytes remaining in buffer */
  53.     int          needData;     /* 1 if need to read data */
  54. } TCPPrivRec, *TCPPrivPtr;
  55.  
  56. typedef enum {
  57.     TCP_READ, TCP_WRITE
  58. } IoOperation;
  59.  
  60. /*
  61.  * REASONABLE_TIME is the amount of time we'll wait for a client connection
  62.  * to unblock, while MAX_BLOCK is the number of times we'll let the connection
  63.  * block us before aborting the whole shebang.
  64.  */
  65. #define REASONABLE_TIME        4
  66. #define MAX_BLOCK         2
  67.  
  68. static void TCPCloseClient();
  69. static char *TCPReadClient();
  70. static int  TCPWriteClient();
  71.  
  72. /*-
  73.  *-----------------------------------------------------------------------
  74.  *
  75.  * TCP_Init --
  76.  *    Initialize the TCP module by creating the passive socket and
  77.  *    storing its stream ID in TCP_Conn.
  78.  *
  79.  * Results:
  80.  *    None.
  81.  *
  82.  * Side Effects:
  83.  *    A passive socket is opened and its streamID placed in TCP_Conn.
  84.  *
  85.  *-----------------------------------------------------------------------
  86.  */
  87. void
  88. TCP_Init()
  89. {
  90.     struct sockaddr_in    inAddr;
  91.     int                  displayNum;
  92.     struct sigvec      ignore;
  93.  
  94.     displayNum = atoi(display);
  95.     inAddr.sin_port = htons(X_TCP_PORT + displayNum);
  96.     inAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  97.  
  98.     TCP_Conn = socket(AF_INET, SOCK_STREAM, 0);
  99.     if (TCP_Conn < 0) {
  100.     Error("Creating TCP socket");
  101.     FatalError("Couldn't create TCP socket...\n");
  102.     /*NOTREACHED*/
  103.     }
  104.     if (bind(TCP_Conn, (struct sockaddr *) &inAddr, sizeof(inAddr)) < 0) {
  105.     Error("Binding TCP socket");
  106.     FatalError("Couldn't bind TCP socket...\n");
  107.     /*NOTREACHED*/
  108.     }
  109.     if (listen(TCP_Conn, 5) < 0) {
  110.     Error("listen(TCP_Conn)");
  111.     FatalError("Couldn't listen on TCP socket...\n");
  112.     /*NOTREACHED*/
  113.     }
  114.     (void)Ioc_SetBits(TCP_Conn, IOC_NON_BLOCKING);
  115.     ignore.sv_handler = SIG_IGN;
  116.     ignore.sv_mask = ignore.sv_onstack = 0;
  117.     sigvec(SIGPIPE, &ignore, (struct sigvec *) 0);
  118. }
  119.  
  120. /*-
  121.  *-----------------------------------------------------------------------
  122.  *
  123.  * TCPConnIO --
  124.  *    Perform some I/O on a tcp connection with timeouts.
  125.  *
  126.  * Results:
  127.  *    Zero is returned if the operation completed successfully,
  128.  *    a non-zero errno otherwise.
  129.  *
  130.  * Side Effects:
  131.  *    The data are transmitted or received.
  132.  *
  133.  *-----------------------------------------------------------------------
  134.  */
  135. static ReturnStatus
  136. TCPConnIO(streamID, numBytes, bufPtr, ioType)
  137.     int              streamID;
  138.     int              numBytes;
  139.     Address       bufPtr;
  140.     IoOperation      ioType;
  141. {
  142.     struct timeval      timeout;
  143.     int                  *selMask;
  144.     int                  numIO;
  145.     int                  timesBlocked;
  146.  
  147.     Bit_Alloc(streamID+1, selMask);
  148.     timesBlocked = 0;
  149.     while (1) {
  150.     if (ioType == TCP_WRITE) {
  151.         numIO = write(streamID, bufPtr, numBytes);
  152.     } else {
  153.         numIO = read(streamID, bufPtr, numBytes);
  154.     }
  155.     if (numIO != -1) {
  156.         /*
  157.          * I/O was successful, but it might have been short. Subtract
  158.          * the number of bytes dealt with from that we have to handle
  159.          * and if it's zero, we've finished successfully. Else keep
  160.          * going.
  161.          */
  162.         numBytes -= numIO;
  163.         bufPtr += numIO;
  164.         if (numBytes == 0) {
  165.         Bit_Free(selMask);
  166.         return (0);
  167.         }
  168.     } else if (errno == EWOULDBLOCK) {
  169.         /*
  170.          * The operation blocked. We only allow the client to block us
  171.          * a certain number of times before we return an error. If we're
  172.          * still being patient, we select on the stream for a reasonable
  173.          * time and loop once it's ready or the time has expired.
  174.          */
  175.         timesBlocked += 1;
  176.         if (timesBlocked > MAX_BLOCK) {
  177.         Bit_Free(selMask);
  178.         return (EWOULDBLOCK);
  179.         }
  180.  
  181.         timeout.tv_sec = REASONABLE_TIME;
  182.         timeout.tv_usec = 0;
  183.         do {
  184.         Bit_Set(streamID, selMask);
  185.         numIO = select(streamID+1, 
  186.                (ioType == TCP_READ ? selMask : (int *) 0),
  187.                (ioType == TCP_WRITE ? selMask : (int *) 0),
  188.                (int *) 0, &timeout);
  189.         } while (errno == EINTR);
  190.     } else {
  191.         /*
  192.          * Some other error occurred. Abort and return it.
  193.          */
  194.         Bit_Free(selMask);
  195.         return (errno);
  196.     }
  197.     }
  198. }
  199.  
  200. /*-
  201.  *-----------------------------------------------------------------------
  202.  *
  203.  * TCPClientAuthorized --
  204.  *    See if a client that is connecting over TCP is authorized to do
  205.  *    so.
  206.  *
  207.  * Results:
  208.  *    1 if the connection is OK. 0 otherwise.
  209.  *
  210.  * Side Effects:
  211.  *    *pSwapped is set 1 if the client needs to be byte-swapped.
  212.  *    *pReason points to a reason for the refusal, if such there be.
  213.  *
  214.  *-----------------------------------------------------------------------
  215.  */
  216. static int
  217. TCPClientAuthorized(conn, pSwapped, pInAddr, pReason)
  218.     int                  conn;          /* StreamID of connection */
  219.     Bool              *pSwapped;  /* OUT: True if client is byte-swapped */
  220.     struct sockaddr    *pInAddr;   /* Address of connected client */
  221.     char              **pReason;  /* OUT: Reason for refusal */
  222. {
  223.     xConnClientPrefix    xccp;        /* Prefix of info from client */
  224.     
  225.     *pReason = (char *)NULL;
  226.     
  227.     if (TCPConnIO(conn, sizeof(xccp), &xccp, TCP_READ) != 0) {
  228.     if (DBG(TCP)) {
  229.         Error("Reading client prefix");
  230.     }
  231.     *pReason = "Couldn't read client prefix";
  232.     return (0);
  233.     }
  234.     if (xccp.byteOrder != whichByteIsFirst) {
  235.     SwapConnClientPrefix(&xccp);
  236.     *pSwapped = 1;
  237.     } else {
  238.     *pSwapped = 0;
  239.     }
  240.  
  241.     if ((xccp.majorVersion != X_PROTOCOL) ||
  242.     (xccp.minorVersion != X_PROTOCOL_REVISION)) {
  243.         *pReason = "Protocol version mismatch";
  244.         return (0);
  245.     }
  246.  
  247.     if (InvalidHost(FamilyInternet, pInAddr)) {
  248.     *pReason = "Permission denied";
  249.     return (0);
  250.     }
  251.     if (xccp.nbytesAuthProto != 0) {
  252.     char *authProto;
  253.  
  254.     authProto = (char *)ALLOCATE_LOCAL(xccp.nbytesAuthProto);
  255.     if (TCPConnIO(conn, xccp.nbytesAuthProto, authProto,
  256.               TCP_READ) != 0) {
  257.             *pReason = "Couldn't read authorization protocol string";
  258.             DEALLOCATE_LOCAL(authProto);
  259.             return (0);
  260.     }
  261.     DEALLOCATE_LOCAL(authProto);
  262.     }
  263.     if (xccp.nbytesAuthString != 0) {
  264.     char *authString;
  265.  
  266.     authString = (char *)ALLOCATE_LOCAL(xccp.nbytesAuthString);
  267.     if (TCPConnIO(conn, xccp.nbytesAuthString, authString,
  268.               TCP_READ) != 0) {
  269.                 *pReason = "Couldn't read authorization string";
  270.                 DEALLOCATE_LOCAL(authString);
  271.                 return (0);
  272.     }
  273.     DEALLOCATE_LOCAL(authString);
  274.     }
  275.     return (1);
  276. }
  277.  
  278. /*-
  279.  *-----------------------------------------------------------------------
  280.  *
  281.  * TCPConnFail --
  282.  *    Report connection failure to the client.
  283.  *
  284.  * Results:
  285.  *    None.
  286.  *
  287.  * Side Effects:
  288.  *    An xConnSetupPrefix is sent.
  289.  *
  290.  *-----------------------------------------------------------------------
  291.  */
  292. static void
  293. TCPConnFail(streamID, swapped, reason)
  294.     int        streamID;
  295.     Bool    swapped;
  296.     char    *reason;
  297. {
  298.     xConnSetupPrefix *packet;
  299.     int        reasonLength;
  300.     int        totalLength;
  301.     int        numWritten;
  302.  
  303.     reasonLength = strlen(reason);
  304.     totalLength = (reasonLength + 3) >> 2;
  305.     
  306.     numWritten = sizeof(xConnSetupPrefix) + (totalLength << 2);
  307.     packet = (xConnSetupPrefix *)ALLOCATE_LOCAL(numWritten);
  308.  
  309.     packet->success = xFalse;
  310.     packet->lengthReason = reasonLength;
  311.     packet->length = totalLength;
  312.     if (!swapped) {
  313.     packet->majorVersion = X_PROTOCOL;
  314.     packet->minorVersion = X_PROTOCOL_REVISION;
  315.     } else {
  316.     short      n;
  317.  
  318.     swaps(&packet->length, n);
  319.     packet->majorVersion = lswaps(X_PROTOCOL);
  320.     packet->minorVersion = lswaps(X_PROTOCOL_REVISION);
  321.     }
  322.     strcpy ((char *)(packet+1), reason);
  323.     (void)TCPConnIO(streamID, numWritten, packet, TCP_WRITE);
  324.     DEALLOCATE_LOCAL(packet);
  325. }
  326.  
  327. /*-
  328.  *-----------------------------------------------------------------------
  329.  *
  330.  * TCP_EstablishNewConnections --
  331.  *    A connection has been discovered on the passive TCP socket, so
  332.  *    we accept it and do all the things we're supposed to do...
  333.  *
  334.  *    XXX: Only accept one new connection, should we accept more?
  335.  *
  336.  * Results:
  337.  *    None.
  338.  *
  339.  * Side Effects:
  340.  *    A new ClientPtr is placed in the passed array and the number of
  341.  *    new clients is incremented.
  342.  *
  343.  *-----------------------------------------------------------------------
  344.  */
  345. void
  346. TCP_EstablishNewConnections(pNewClients, pNumNew)
  347.     ClientPtr          *pNewClients;
  348.     int                  *pNumNew;
  349. {
  350.     int                  newID;        /* New client stream */
  351.     ClientPtr          client;        /* New client record */
  352.     struct sockaddr    inAddr;        /* Address of new client */
  353.     int                  addrLen;    /* Length of new client's address */
  354.     int           swapped;    /* 1 if client is byte-swapped */
  355.     ClntPrivPtr          pPriv;        /* OS-global private data for client */
  356.     TCPPrivPtr          ptcpPriv;   /* Our private data */
  357.     char              *reason;    /* Reason for connection refusal */
  358.     
  359.     pNewClients += *pNumNew;
  360.  
  361.     addrLen = sizeof(inAddr);
  362.     newID = accept(TCP_Conn, &inAddr, &addrLen);
  363.     if (newID < 0) {
  364.     if (DBG(TCP)) {
  365.         Error("accept");
  366.     }
  367.     return;
  368.     }
  369.     if (!TCPClientAuthorized(newID, &swapped, &inAddr, &reason)) {
  370.     if (DBG(TCP)) {
  371.         ErrorF("Unauthorized connection\n");
  372.     }
  373.     TCPConnFail(newID, swapped, reason);
  374.     close(newID);
  375.     return;
  376.     }
  377.     client = (ClientPtr) NextAvailableClient();
  378.     if (client == NullClient) {
  379.     if (DBG(TCP)) {
  380.         ErrorF("No more clients!\n");
  381.     }
  382.     TCPConnFail(newID, swapped, "No more client slots");
  383.     close(newID);
  384.     return;
  385.     }
  386.     pPriv = (ClntPrivPtr) malloc(sizeof(ClntPrivRec));
  387.     pPriv->readProc = TCPReadClient;
  388.     pPriv->writeProc = TCPWriteClient;
  389.     pPriv->closeProc = TCPCloseClient;
  390.     pPriv->ready = pPriv->mask = (int *)0;
  391.     pPriv->maskWidth = 0;
  392.     
  393.     ptcpPriv = (TCPPrivPtr) malloc(sizeof(TCPPrivRec));
  394.     pPriv->devicePrivate = (pointer)ptcpPriv;
  395.     
  396.     client->osPrivate = (pointer)pPriv;
  397.     client->swapped = swapped;
  398.     
  399.     ptcpPriv->streamID = newID;
  400.     ptcpPriv->client = client;
  401.     ptcpPriv->buffer = (Address)NULL;
  402.     ptcpPriv->numBytes = 0;
  403.     ptcpPriv->needData = 1;
  404.     
  405.     ExpandMasks(pPriv, newID);
  406.     
  407.     Ioc_SetBits(newID, IOC_NON_BLOCKING);
  408.     
  409.     if (GrabDone) {
  410.     Bit_Set(newID, SavedAllClientsMask);
  411.     Bit_Set(newID, SavedAllStreamsMask);
  412.     } else {
  413.     Bit_Set(newID, AllClientsMask);
  414.     Bit_Set(newID, AllStreamsMask);
  415.     }
  416.     if (DBG(TCP) || DBG(CONN)) {
  417.     ErrorF("New TCP connection: client %d (newID = %d)\n", client->index,
  418.            newID);
  419.     }
  420.     *pNewClients = client;
  421.     pNewClients++;
  422.     (*pNumNew)++;
  423. }
  424.  
  425. /*-
  426.  *-----------------------------------------------------------------------
  427.  *
  428.  * TCPCloseClient --
  429.  *    Close down a client we're handling and free up our part of the
  430.  *    resources.
  431.  *
  432.  * Results:
  433.  *    None.
  434.  *
  435.  * Side Effects:
  436.  *    The active stream to the client is closed and the private data
  437.  *    freed. The stream is removed from these masks: 
  438.  *        AllStreamsMask, SavedAllStreamsMask, AllClientsMask,
  439.  *        SavedAllClientsMask, ClientsWithInputMask
  440.  *
  441.  *-----------------------------------------------------------------------
  442.  */
  443. static void
  444. TCPCloseClient(pPriv)
  445.     ClntPrivPtr      pPriv;        /* Private data for client to be closed */
  446. {
  447.     TCPPrivPtr      ptcpPriv;
  448.  
  449.     ptcpPriv = (TCPPrivPtr)pPriv->devicePrivate;
  450.  
  451.     if (ptcpPriv->buffer) {
  452.     free((char *) ptcpPriv->buffer);
  453.     }
  454.     Bit_Clear(ptcpPriv->streamID, ClientsWithInputMask);
  455.  
  456.     if (GrabDone) {
  457.     Bit_Clear(ptcpPriv->streamID, SavedAllClientsMask);
  458.     Bit_Clear(ptcpPriv->streamID, SavedAllStreamsMask);
  459.     if (grabbingClient == ptcpPriv->client) {
  460.         Bit_Clear(ptcpPriv->streamID, AllClientsMask);
  461.         Bit_Clear(ptcpPriv->streamID, AllStreamsMask);
  462.     }
  463.     } else {
  464.     Bit_Clear(ptcpPriv->streamID, AllClientsMask);
  465.     Bit_Clear(ptcpPriv->streamID, AllStreamsMask);
  466.     }
  467.     free((char *)ptcpPriv);
  468. }
  469.  
  470. #define request_length(req, cli) \
  471.      (((cli)->swapped?lswaps(((xReq *)(req))->length):\
  472.       ((xReq *)(req))->length) << 2)
  473. /*-
  474.  *-----------------------------------------------------------------------
  475.  *
  476.  * TCPReadClient --
  477.  *    Read a request from the given client.
  478.  *
  479.  * Results:
  480.  *    Pointer to the start of the request.
  481.  *
  482.  * Side Effects:
  483.  *    Data may be read from the client's connection.
  484.  *
  485.  *-----------------------------------------------------------------------
  486.  */
  487. /*ARGSUSED*/
  488. static char *
  489. TCPReadClient(pPriv, pStatus, oldbuf)
  490.     ClntPrivPtr      pPriv;        /* Client with input */
  491.     int              *pStatus;     /* Result of read:
  492.                  *  >0 -- number of bytes in request
  493.                  *   0 -- not all the request is there
  494.                  *  <0 -- error */
  495.     char          *oldbuf;      /* Previous buffer */
  496. {
  497.     xReq          *reqPtr;      /* Request being returned */
  498.     int              numRead;      /* Number of bytes read from the socket */
  499.     int              need;            /* Number of bytes needed */
  500.     TCPPrivPtr      ptcpPriv;     /* Our private data for the client */
  501.  
  502.     ptcpPriv = (TCPPrivPtr)pPriv->devicePrivate;
  503.  
  504.     Bit_Clear(ptcpPriv->streamID, ClientsWithInputMask);
  505.  
  506.     if (ptcpPriv->needData) {
  507.     /*
  508.      * If previous buffer was exhausted and we haven't freed it, do so
  509.      * now. While we could just keep the buffer around, thereby adjusting
  510.      * it to the usual size the client will need, it could easily get
  511.      * out of hand if someone sends a good bit of image data, so
  512.      * we pay the price of copying rather than that of having buffers be
  513.      * too large.
  514.      */
  515.     if ((ptcpPriv->numBytes == 0) && (ptcpPriv->buffer != (Address)NULL)){
  516.         free((char *) ptcpPriv->buffer);
  517.         ptcpPriv->buffer = (Address)NULL;
  518.     }
  519.     need = -1;
  520.     if ((Ioc_NumReadable(ptcpPriv->streamID, &need) != SUCCESS) ||
  521.         (need <= 0)) {
  522.         /*
  523.          * If there are no bytes waiting, the other side has closed its
  524.          * connection (we could only have gotten here if the select
  525.          * returned readable, which implies that there are bytes to be
  526.          * read...), so we mark an error. (Also mark an error if
  527.          * we couldn't find how many bytes were available).
  528.          */
  529.         if (DBG(TCP)) {
  530.             ErrorF("Ioc_NumReadable: %d bytes readable\n", need);
  531.         }
  532.         *pStatus = -1;
  533.         return((char *)NULL);
  534.     }
  535.  
  536.     if (ptcpPriv->numBytes != 0) {
  537.         /*
  538.          * There were insufficient data in the buffer last time. We
  539.          * need to compress the buffer as much as possible to keep it
  540.          * from growing without bound (hard to do, but possible).
  541.          * If the space we've allocated already is big enough to
  542.          * hold the current data plus what's coming in now, we just copy
  543.          * the data in place, else we copy it to a new buffer and free
  544.          * the old one.
  545.          */
  546.         char  *newBuffer;
  547.         
  548.         if (Mem_Size(ptcpPriv->buffer) >= need + ptcpPriv->numBytes) {
  549.         newBuffer = ptcpPriv->buffer;
  550.         } else {
  551.         newBuffer = malloc(need + ptcpPriv->numBytes);
  552.         }
  553.         if (ptcpPriv->bufPtr != newBuffer) {
  554.         bcopy(ptcpPriv->bufPtr, newBuffer, ptcpPriv->numBytes);
  555.         }
  556.         if (newBuffer != ptcpPriv->buffer) {
  557.         free((char *) ptcpPriv->buffer);
  558.         ptcpPriv->buffer = newBuffer;
  559.         }
  560.     } else {
  561.         ptcpPriv->buffer = malloc(need);
  562.     }
  563.     /*
  564.      * Read whatever data are available from the socket to the end of the
  565.      * buffer. Any error (including FS_WOULD_BLOCK) causes the connection
  566.      * to be severed (we shouldn't block since we're reading what's there)
  567.      */
  568.     numRead = read(ptcpPriv->streamID,
  569.         ptcpPriv->buffer + ptcpPriv->numBytes, need);
  570.     if (numRead == -1) {
  571.         if (DBG(TCP)) {
  572.         Error("Reading TCP connection %d",
  573.               ptcpPriv->streamID);
  574.         }
  575.         *pStatus = -1;
  576.         return ((char *)NULL);
  577.     }
  578.     ptcpPriv->bufPtr = ptcpPriv->buffer;
  579.     ptcpPriv->numBytes += numRead;
  580.  
  581.     }
  582.     /*
  583.      * bufPtr now points to the current request for the client. Figure out how
  584.      * much data must be in the buffer for the request to be complete and store
  585.      * it in 'need'. If there isn't that much data, we have an incomplete
  586.      * request and need to read more data, so we set needData 1 and return
  587.      * a status of 0.
  588.      *
  589.      * If there is enough data, we update the various pointers and whatnot to
  590.      * reflect the taking of the request, then if there's still data in the
  591.      * buffer, note this client as having more input by setting the bit for the
  592.      * stream in the ClientsWithInputMask. The scheduler will exhaust this
  593.      * data before going to sleep again. While it is possible for a client to
  594.      * monopolize the server by cleverly sending incomplete data packets
  595.      * at just the right time, it seems unlikely that it could manage it.
  596.      */
  597.     if (ptcpPriv->numBytes < sizeof(xReq)) {
  598.     ptcpPriv->needData = 1;
  599.     *pStatus = 0;
  600.     SchedYield();
  601.     return ((char *)NULL);
  602.     }
  603.     need = request_length(ptcpPriv->bufPtr, ptcpPriv->client);
  604.     if (need > ptcpPriv->numBytes) {
  605.     ptcpPriv->needData = 1;
  606.     *pStatus = 0;
  607.     SchedYield();
  608.     return ((char *)NULL);
  609.     }
  610.     reqPtr = (xReq *)ptcpPriv->bufPtr;
  611.     ptcpPriv->bufPtr += need;
  612.     ptcpPriv->numBytes -= need;
  613.     *pStatus = need;
  614.     ptcpPriv->needData = 1;
  615.     
  616.     if (ptcpPriv->numBytes) {
  617.     if (ptcpPriv->numBytes >= sizeof(xReq)) {
  618.         need = request_length(ptcpPriv->bufPtr, ptcpPriv->client);
  619.         if (ptcpPriv->numBytes >= need) {
  620.         /*
  621.          * We only don't need data in the buffer if we have a
  622.          * complete request sitting there. In such a case, we mark
  623.          * the client as already having input and set needData 0.
  624.          */
  625.         Bit_Set(ptcpPriv->streamID, ClientsWithInputMask);
  626.         ptcpPriv->needData = 0;
  627.         }
  628.     }
  629.     }
  630.     if (ptcpPriv->needData) {
  631.     /*
  632.      * Once we run out of data in the request buffer, we have to wait
  633.      * for another select to return this stream's readiness.
  634.      */
  635.     SchedYield();
  636.     }
  637.     return ((char *)reqPtr);
  638. }
  639.  
  640. /*-
  641.  *-----------------------------------------------------------------------
  642.  *
  643.  * TCPWriteClient --
  644.  *    Write information to the client. We have a choice of making
  645.  *    two write calls or copying the data to longword-align it. For
  646.  *    now, just make the two system calls. We'll see which is worse...
  647.  *    We could use writev, but that's not restartable in case
  648.  *    of an interrupt.
  649.  *
  650.  * Results:
  651.  *    The number of bytes written.
  652.  *
  653.  * Side Effects:
  654.  *    Data are written to
  655.  *
  656.  *-----------------------------------------------------------------------
  657.  */
  658. static int
  659. TCPWriteClient (pPriv, numBytes, xRepPtr)
  660.     ClntPrivPtr      pPriv;
  661.     int              numBytes;
  662.     Address       xRepPtr;
  663. {
  664.     TCPPrivPtr      ptcpPriv;
  665.     int              pad = 0;
  666.     int              numPadBytes;
  667.  
  668.     ptcpPriv = (TCPPrivPtr)pPriv->devicePrivate;
  669.     numPadBytes = (4 - (numBytes & 3)) & 3;
  670.  
  671.     if (TCPConnIO(ptcpPriv->streamID, numBytes, xRepPtr, TCP_WRITE)!=0){
  672.     MarkClientException(ptcpPriv->client);
  673.     return(-1);
  674.     }
  675.     if (numPadBytes &&
  676.     (TCPConnIO(ptcpPriv->streamID, numPadBytes,&pad,TCP_WRITE)!=0)){
  677.     MarkClientException(ptcpPriv->client);
  678.     return(-1);
  679.     }
  680.     return (numBytes);
  681. }
  682. #endif TCPCONN
  683.